﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;

namespace WebApplication1.Controllers
{
    public class WebSocketController : ControllerBase
    {
        private static List<WebSocket> _clients = new List<WebSocket>();

        [HttpGet("/ws")]
        public async Task Get() {
            if (HttpContext.WebSockets.IsWebSocketRequest)
            {
                using WebSocket webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();

                string clientId = Guid.NewGuid().ToString();
                var wsClient = new WebsocketClient
                {
                    Id = clientId,
                    webSocket = webSocket,
                    userid = ""
                };

                try
                {
                    await Handle(wsClient);
                }
                catch (Exception ex)
                {
                    await HttpContext.Response.WriteAsync("closed");
                    //throw ex;
                }
            }
            else
            {
                HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
            }
        }

        private async Task Handle(WebsocketClient websocketClient)
        {
            try
            {
                WebsocketClientCollection.Add(websocketClient);

                var buffer = new byte[1024 * 4];
                WebSocketReceiveResult result = await websocketClient.webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                while (!result.CloseStatus.HasValue)
                {
                    
                    if (result.MessageType == WebSocketMessageType.Text && !result.CloseStatus.HasValue)
                    {
                        string msgString = System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count);
                        try
                        {
                            Message message = JsonConvert.DeserializeObject<Message>(msgString);
                            message.receiveTime = DateTime.Now;
                            message.sendClientId = websocketClient.Id;
                            this.HandleMessage(message);
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }

                    result = await websocketClient.webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                }
                //关闭客户端
                await websocketClient.webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
                //关掉使用WebSocket连接的网页/调用webSocket.close()后，与之对应的后台会跳出循环
                WebsocketClientCollection.Remove(websocketClient);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 消息处理
        /// </summary>
        /// <param name="message"></param>
        private void HandleMessage(Message message)
        {
            //WebsocketClient client = WebsocketClientCollection.Get(message.sendClientId);
            var clients = WebsocketClientCollection.GetAll();
            switch (message.action)
            {
                case "join": // 加入
                    
                    foreach (WebsocketClient item in clients)
                    {
                        string str = JsonConvert.SerializeObject(message);
                        item.SendMessageAsync(str);
                    };
                    break;
                case "send_to_single": // 发给单个人
                    break;
                case "send_to_group": // 发给某个组的人员
                    break;
                case "leave": // 离开
                    break;
                default://send_to_all
                    foreach (WebsocketClient item in clients)
                    {
                        try
                        {
                            byte[] bytes = Convert.FromBase64String(message.content);
                            message.content = System.Text.Encoding.UTF8.GetString(bytes);
                        }
                        catch (Exception ex)
                        {
                            message.content = message.content;
                        }                        
                        
                        string str = JsonConvert.SerializeObject(message);
                        item.SendMessageAsync(str);
                    }
                    break;
            }
        }
    }
}
